package com.oyjd.fw.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * FTP处理工具
 * 
 * @author <b>欧建东<br/>
 *         Email:oyjd@163.com</b>
 * 
 */
public class FtpUtil {
	private static final Log log = LogFactory.getLog(FtpUtil.class);

	private static final int BufferSize = 10240;
	private static String encoding = "GBK";
	private static List<String> ym;
	private static String musicLogPath;
	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");

	/**
	 * Description: 向FTP服务器上传文件
	 * 
	 * @param url
	 *            FTP服务器hostname
	 * @param port
	 *            FTP服务器端口
	 * @param username
	 *            FTP登录账号
	 * @param password
	 *            FTP登录密码
	 * @param path
	 *            FTP服务器保存目录
	 * @param filename
	 *            上传到FTP服务器上的文件名
	 * @param input
	 *            输入流
	 * @return 成功返回true，否则返回false
	 */
	public static boolean uploadFile(String url, int port, String username, String password, String path, String filename, InputStream input) {
		boolean success = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			ftp.connect(url, port);// 连接FTP服务器
			// 如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
			ftp.login(username, password);// 登录
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return success;
			}
			ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftp.setBufferSize(BufferSize);
			ftp.setControlEncoding(encoding);
			ftp.enterLocalPassiveMode();
			ftp.changeWorkingDirectory(path);
			ftp.storeFile(filename, input);

			input.close();
			ftp.logout();
			success = true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (Exception ioe) {
				}
			}
		}
		return success;
	}

	/**
	 * Description: 从FTP服务器下载文件
	 * 
	 * @param url
	 *            FTP服务器hostname
	 * @param port
	 *            FTP服务器端口
	 * @param username
	 *            FTP登录账号
	 * @param password
	 *            FTP登录密码
	 * @param remotePath
	 *            FTP服务器上的相对路径，需要以'/'结尾
	 * @param fileName
	 *            要下载的文件名
	 * @param localPath
	 *            下载后保存到本地的路径，需要以'/'结尾
	 * @return
	 */
	public static boolean downFile(String url, int port, String username, String password, String remotePath, String fileName, String localPath) {
		boolean success = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			ftp.connect(url, port);
			// 如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
			ftp.login(username, password);// 登录
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return success;
			}
			ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftp.setBufferSize(BufferSize);
			ftp.setControlEncoding(encoding);
			ftp.enterLocalPassiveMode();
			ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录

			FTPFile[] fs = ftp.listFiles();
			for (FTPFile ff : fs) {
				if (ff.getName().equals(fileName)) {
					File localFile = new File(localPath + "/" + ff.getName());
					OutputStream is = new FileOutputStream(localFile);
					ftp.retrieveFile(ff.getName(), is);
					is.close();
				}
			}
			ftp.logout();
			success = true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (Exception ioe) {
				}
			}
		}
		return success;
	}

	/**
	 * 同步文件夹
	 * 
	 * @param url
	 *            FTP服务器hostname
	 * @param port
	 *            FTP服务器端口
	 * @param username
	 *            FTP登录账号
	 * @param password
	 *            FTP登录密码
	 * @param remotePath
	 *            FTP服务器上的相对路径，需要以'/'结尾
	 * @param localPath
	 *            下载后保存到本地的路径，需要以'/'结尾
	 * @return
	 */
	public static boolean synDir(String url, int port, String username, String password, String remotePath, String localPath) {
		boolean success = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			ftp.connect(url, port);
			log.info("----------连接到Ftp服务器成功！----------");
			ftp.login(username, password);// 登录
			log.info("----------登录Ftp服务器成功！----------");
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return success;
			}
			ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftp.setBufferSize(BufferSize);
			ftp.setControlEncoding(encoding);
			ftp.enterLocalPassiveMode();
			doFold(ftp, remotePath, localPath);
			ftp.logout();
			log.info("----------登出Ftp服务器！----------");
			success = true;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
					log.info("----------断开Ftp服务器连接！----------");
				} catch (Exception ioe) {
				}
			}
		}
		return success;
	}

	/**
	 * 迭代文件
	 * 
	 * @param ftp
	 * @param remotePath
	 * @param localPath
	 * @throws IOException
	 */
	private static void doFold(FTPClient ftp, String remotePath, String localPath) throws Exception {
		log.info("----------同步目录:" + remotePath + "--->" + localPath);
		new File(localPath).mkdirs();
		ftp.changeWorkingDirectory(remotePath);
		FTPFile[] fs = ftp.listFiles(remotePath);
		List<String> dirs = new ArrayList<String>();
		for (FTPFile f : fs) {
			if (f.isFile()) {
				String path = localPath + f.getName();
				try {
					File ff = new File(path);
					if (ff.exists() && ff.length() == f.getSize()) {
						continue;
					}
					ff.delete();
					OutputStream is = new FileOutputStream(ff);
					// 需要转成iso-8859-1
					String tmpName = new String(f.getName().getBytes(encoding), "iso-8859-1");
					ftp.retrieveFile(tmpName, is);
					is.close();
					bornChk(path);
					log.info("--->完成：" + path);
				} catch (Exception err) {
					log.error(err.getMessage(), err);
				}
			} else if (f.isDirectory() && !f.getName().startsWith(".")) {
				dirs.add(f.getName());
			}
		}
		// 处理目录,由于ftp.changeWorkingDirectory(remotePath);
		// 需要转移工作目录，直接在循环里调用将使后循环的目录错乱
		for (String s : dirs) {
			if (remotePath.equals("/")) {
				if (ym.contains(s)) {
					// 如果有记录，当在当前月和上一月，仍然进行一次同步检测
					Calendar c = Calendar.getInstance();
					String m1 = sdf.format(c.getTime());
					c.add(Calendar.MONTH, -1);
					String m2 = sdf.format(c.getTime());
					if (m1.equals(s) || m2.equals(s)) {
						doFold(ftp, remotePath + s + "/", localPath + s + "/");
					} else {
						log.info("----------跳过完成目录:" + s);
					}
				} else {
					doFold(ftp, remotePath + s + "/", localPath + s + "/");
					FileOP.writeFile(musicLogPath, s + "\r\n", encoding, true);
					ym.add(s);
				}
			} else {
				doFold(ftp, remotePath + s + "/", localPath + s + "/");
			}
		}
	}

	/**
	 * 生成校验文件
	 * 
	 * @param name
	 *            文件全路径名
	 * @throws Exception
	 */
	private static void bornChk(String name) throws Exception {
		long size = new File(name).length();
		String chkPath = name + ".zmck";
		new File(chkPath).delete();
		FileOP.writeFile(chkPath, System.currentTimeMillis() + "|" + size, encoding);
	}

	public static void main(String[] args) {
		log.info("===============开始同步===============");
		try {
			Map<String, String> m = PropUtil.read();
			String musicFtpIP = m.get("musicFtpIP");
			int musicFtpPort = Integer.parseInt(m.get("musicFtpPort"));
			String musicFtpAccount = m.get("musicFtpAccount");
			String musicFtpPwd = m.get("musicFtpPwd");
			String musicSavePath = m.get("musicSavePath");
			musicLogPath = m.get("musicLogPath");
			log.info("----------读取配置文件成功！----------");
			ym = new ArrayList<String>();
			File logF = new File(musicLogPath);
			if (logF.exists()) {
				String c = FileOP.readFile(musicLogPath, encoding);
				for (String s : c.split("\r\n")) {
					ym.add(s);
				}
			} else {
				logF.getParentFile().mkdirs();
			}
			log.info("----------读取日志文件成功！----------");
			synDir(musicFtpIP, musicFtpPort, musicFtpAccount, musicFtpPwd, "/", musicSavePath);
		} catch (Exception err) {
			log.error(err.getMessage(), err);
		}
		log.info("===============结束同步===============");

		System.exit(0);
	}

}
